﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;

namespace Zhaoxi.ThreadShow
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        #region 多线程：Thread:

        /// <summary>
        /// 多线程：Thread:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ThreadBtn_Click(object sender, EventArgs e)
        {
            Console.WriteLine($"****************ThreadBtn_Click Start  ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            //多线程就是从这里开始的  
            //Thread thread = new Thread(() => Console.WriteLine("欢迎大家来到高级本的体验课！"));


            //Thread thread = new Thread(() =>
            //{
            //    this.DoCostTimeMethod("fresh");
            //});
            //thread.Start();//开启了一个线程

            {
                //Thread thread = new Thread(o => Console.WriteLine($"这里是开启了一个线程 {Thread.CurrentThread.ManagedThreadId.ToString("00")} 结果为：{o}"));
                //thread.Start("Joer2鹏");
            }
            {
                //thread.Suspend();//暂停
                //thread.Resume();//让暂停的线程继续执行。。。
                //thread.Abort();//线程要终止
                //Thread.ResetAbort();//终止的线程可以继续运行
                //Thread.Sleep(2000); //主线程等待2秒钟；
                //thread.Join();//thread等待等待 代码执行到这里会卡住
                //thread.Join(2000); //限时等待  过时不候
                //while (thread.ThreadState!=ThreadState.Stopped)
                //{
                //    Thread.Sleep(2000);
                //} 
                //thread.Priority = ThreadPriority.Highest;//最好不通过他来控制线程 只能从概念上来增加他的优先级
                //thread.IsBackground = true;//进程关闭  线程也就随之取消
                //thread.IsBackground = false;
            }
            {
                //While  await 他会卡顿界面；
                //Thread 没有线程的Api来控制线程顺序 
                //使用多线程：不会卡顿界面；
                //关于委托的详解：大家添加一下课堂的助教微信 有专门的委托课程分享；

                //Action threadStart = new Action(() =>
                //{
                //    this.DoCostTimeMethod("fresh");
                //});
                //Action action = () => Console.WriteLine("这是上一个线程执行完毕以后执行的动作");
                //this.ThreadWithCallBack(threadStart, action);
                ////如果我需要返回值呢？ 
                Func<int> func = () =>
                {
                    return DateTime.Now.Year;
                };
                //int iResult = ThreadWithReturn(func); 
                Func<int> fResult = ThreadWithReturn(func);
                Console.WriteLine("this is ....");
                Console.WriteLine("this is ....");
                Console.WriteLine("this is ....");
                int iResult = fResult.Invoke();

            }
            Console.WriteLine($"****************ThreadBtn_Click End    ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }
        /// <summary>
        /// 如何保证不卡顿界面；让两个委托中的任务有序执行？
        /// </summary>
        /// <param name="threadStart"></param>
        /// <param name="action"></param>
        private void ThreadWithCallBack(Action threadStart, Action action)
        {
            ///在这里开启一个线程去执行这两个委托
            ThreadStart start = () =>
              {
                  threadStart.Invoke();
                  action.Invoke();
              };
            new Thread(start).Start();
        }

        private Func<T> ThreadWithReturn<T>(Func<T> func)
        {
            T t = default(T);
            ThreadStart threadStart = () =>
            {
                t = func.Invoke();
            };
            Thread thread = new Thread(threadStart);
            thread.Start();
            return new Func<T>(() =>
            {
                thread.Join();
                return t;
            });
        }

        /// <summary>
        ///  单纯的只是一个比较耗时的方法
        /// </summary>
        /// <param name="name"></param>
        private void DoCostTimeMethod(string name)
        {
            Console.WriteLine($"****************DoCostTimeMethod Start  {name}  ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(5000);

            Console.WriteLine($"****************DoCostTimeMethod   End  {name}  ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }

        #endregion

        #region 线程池 ThreadPool 
        /// <summary>
        /// 线程池：ThreadPool
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ThreadPoolBtn_Click(object sender, EventArgs e)
        {
            Console.WriteLine($"****************ThreadPoolBtn_Click Start ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            {
                //WaitCallback waitCallback = new WaitCallback(o =>
                //{
                //    this.DoCostTimeMethod(o.ToString()) ;
                //});
                //ThreadPool.QueueUserWorkItem(waitCallback,"极限。。。");//从线程池中获取线程 
            }
            {
                ManualResetEvent mre = new ManualResetEvent(false);
                ThreadPool.QueueUserWorkItem(o =>
                {
                    Console.WriteLine($"this is  {o}");
                    mre.Set();
                });//从线程池中获取线程 
                //线程等待
                mre.WaitOne();
            }

            Console.WriteLine($"****************ThreadPoolBtn_Click End   ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }
        #endregion

        #region 多线程Task
        /// <summary>
        /// C#中的多线程Task
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskBtn_Click(object sender, EventArgs e)
        {
            {
                //Task task = new Task(() =>
                //{
                //    Console.WriteLine($"这是一个线程  线程Id {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                //});
                //task.Start();// 开始线程


                //Task.Run(() =>
                //{
                //    Console.WriteLine($"这是一个线程  线程Id {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                //});

                //TaskFactory taskFactory = new TaskFactory();
                //taskFactory.StartNew(() =>
                //{
                //    Console.WriteLine($"这是一个线程  线程Id {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                //});

                //Task.Factory.StartNew(() =>
                //{
                //    Console.WriteLine($"这是一个线程  线程Id {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                //});
            }


            {
                //{
                //    Stopwatch stopwatch = new Stopwatch();
                //    stopwatch.Start();

                //    Thread.Sleep(5000); //等待  等待1000毫秒   等待的过程中, 阻塞界面, 阻塞主线程~

                //    stopwatch.Stop();
                //    Console.WriteLine($"Thread.Sleep(5000)  耗时多长时间呢?  {stopwatch.ElapsedMilliseconds}=={DateTime.Now}");

                //}

                //{
                //    Stopwatch stopwatch = new Stopwatch();
                //    stopwatch.Start(); 
                //    //线程等待,  等待不阻塞主线程, Delay 和后续还有一个方法一起使用
                //    Task.Delay(5000).ContinueWith((s, y) =>
                //    { 
                //        //异步等待, 一般在Task.Delay(5000) 后面跟一个行为, 行为就是在等待了多长时间后, 去执行这个行为; 
                //        stopwatch.Stop();
                //        Console.WriteLine($"Task.Delay(5000)  耗时多长时间呢?  {stopwatch.ElapsedMilliseconds}");

                //    }, null); 
                //}
            }


            //在开发中,哪些场景可以使用多线程呢?
            //1. 可以并发执行~~  完成一个查询---查询的数据 包含几块数据.  开启多个线程同时去查询, 每个线程查询各自的数据. 
            //2. 查询数据库, 需要第一次查询的之后的结果, 作为第二次查询的的条件~, 不可以~
            {
                //场景: 高级班Vip课程中的场景, 先学习知识点, 然后做项目实战;
                //1.高级进阶编程
                //2.数据库进阶
                //3.跨平台.NET Core 
                //Richard老师一节课一节课的讲解~~
                // 不能多线程---不能并发~~

                //开始项目实战~~ 包含很多模块~~ 可以多个小伙伴儿 同时去开发.
                // 可以多线程吗?  可以的~~

                List<Task> taskList = new List<Task>();

                Console.WriteLine(".NET 高级进阶VIP课程 ,开班了~");
                TeachShow("01 高级编程进阶");
                TeachShow("02 数据库进阶");
                TeachShow("03 跨平台.NET Core");

                Console.WriteLine("开始项目实战了--可以多个人合作完成项目开发~~~~");
                TaskFactory taskFactory = new TaskFactory();

                taskList.Add(taskFactory.StartNew(u => CodingShow("歌者恋歌", "搭建框架~"), "歌者恋歌"));
                taskList.Add(taskFactory.StartNew(u => CodingShow("YnWL", "数据库设计~"), "YnWL"));
                taskList.Add(taskFactory.StartNew(u => CodingShow("李嗨", "WeChat~~"), "李嗨"));
                taskList.Add(taskFactory.StartNew(u => CodingShow("timmy", "业务逻辑处理~~"), "timmy"));

                ////业务需求:  项目开发完毕后,在第一个小伙伴儿完成开发后, Richard老师开始准备发布环境~~
                ////Console.WriteLine("Richard 老师开始准备环境~~"); //不满足诉求
                ////需要保证一定是其中有一个小伙伴儿们完成,开准备环境~~ ???
                //Task.WaitAny(taskList.ToArray());// 等待一堆线程中,其中有一个线程执行结束后, 继续往后执行~~
                //Console.WriteLine("XXX小伙伴儿第一个完成后, 老师就去准备发布环境~~");


                ////业务需求: 所有的对应的功能都完成后,庆祝下, 大吃一顿~
                //Task.WaitAll(taskList.ToArray());  //等待所有的任务都执行完成  继续往后执行~~
                //Console.WriteLine("小伙伴儿们,功能都已完成,庆祝下,大吃一顿~");


                //WaitAll: 使用场景?  
                //某首页数据---需要多块数据查询完成, 统一返回, 定义一个复杂实体. 包含多块数据的属性.
                //对于每一块的查询  可以多线程去查询~   Task.WaitAll  等待所有的线程执行结束, 然后统一返回?

                //WaitAny: 使用场景?
                //查询一个数据列表~~   数据源可能来自于不同的渠道,  可能来自于数据库, 缓存,第三方接口~
                //一般操作--都是先查询缓存, 判断下, 再查询数据库,  判断下,  再查询第三方接口.

                //开启三个线程同时去查询, 一个线程查询数据库, 一个线程查询缓存, 一个线程去查询接口.  
                //等待这一堆任务其中某一个执行完成, 就可以拿到结果.拿到结果后. 其他的线程就可以不管了.  

                //有没有缺陷?---阻塞主线程, 影响用户的体验~~
                //有没有不用阻塞主线程 也能完成以上需求的方法呢?

                //某一个小伙伴儿们, 最先开发完成, 奖励一个小红包.

                //异步等待线程其中一个完成,不会阻塞主线程, 只要是一个线程执行完毕后,就去执行一个动作. 
                taskFactory.ContinueWhenAny(taskList.ToArray(), tak =>
                {
                    //这里的任务执行,可能是上一个线程, 也可能是开启的先线程, 甚至还有可能是主线程来完成.
                    Console.WriteLine($" {tak.AsyncState} 小伙伴儿最先完成功能的开发, 奖励一个小红包~~");
                    //谁先完成的 能不能把名字给输出呢?

                });

                //异步等待所有的线程执行完成~ 去自行一个动作;
                //所有的任务执行完成后. 准备发布部署~
                taskFactory.ContinueWhenAll(taskList.ToArray(), taklist =>
                {
                    //这里的任务执行,可能是上一个线程, 也可能是开启的先线程, 甚至还有可能是主线程来完成.
                    //能不能把名字也给输出呢? 
                    foreach (var item in taklist)
                    {
                        Console.WriteLine($"{item.AsyncState} 完成了");
                    }
                    Console.WriteLine("所有的任务执行完成后. 准备发布部署~~~");
                });
            }

            Console.WriteLine($"****************TaskBtn_Click   End     ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        /// <summary>
        /// 单线程调用方法 耗时耗资源的方法~~
        /// </summary>
        /// <param name="lesson"></param>
        private void TeachShow(string lesson)
        {
            Console.WriteLine($"{lesson}  开始讲解---ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            long lResult = 0;
            Thread.Sleep(1000);
            for (int i = 0; i < 10_000_000; i++)
            {
                lResult += i;
            }
            Console.WriteLine($"{lesson}    结束了---ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            Console.WriteLine("----------------------------------------------------------");
        }

        /// <summary>
        /// 模拟Coding过程
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectName"></param>
        private void CodingShow(string name, string projectName)
        {
            Console.WriteLine($"****************CodingShow Start  {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            Thread.Sleep(2000);
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }
            Console.WriteLine($"****************CodingShow   End  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }

        #endregion

        /// <summary>
        /// 多线程应用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AsyncCorebtn_Click(object sender, EventArgs e)
        {
            Console.WriteLine($"****************AsyncCorebtn_Click Start  ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            {

                //try
                //{
                //    //int i = 0;
                //    //int j = 1;
                //    //int k = j / i;  //必然异常  尝试除以零--不允许  必然异常
                //}
                //catch (Exception)
                //{
                //    ////异常 在这里处理
                //    //throw;
                //}


            }
            //一. 有关于异常的特殊处理~  try-cath



            #region 多线程异常处理 --如何处理呢?
            //异常后, 如何处理呢?
            //在多线程 内部发生了异常之后,  在外面通过try-catch 异常捕捉处理.   捕捉不到. ---异常必然是发生了.  异常去哪儿了?  

            //线程内部发生了异常后,  究竟如何捕捉呢?   需要线程等待~~
            //1. 线程的同步等待
            //2. 异常的捕捉---线程内部发生的异常类型属于AggregateException 类型
            //3. 在try-catch异常捕捉的时候, 可以一个try  多个 catch,  在匹配哦catch类型的时候. 有限匹配具体类型
            {

                //List<Task> tasklist = new List<Task>(); 
                //try
                //{
                //    for (int i = 0; i < 20; i++)
                //    {
                //        string k = $"{i}_AsyncCorebtn_Click";
                //        tasklist.Add(Task.Run(() =>
                //        { 
                //            //try
                //            //{
                //                if (k.Equals("6_AsyncCorebtn_Click"))
                //                {
                //                    throw new Exception("因为k==6_AsyncCorebtn_Click, 所以就异常了");
                //                }
                //                else if (k.Equals("11_AsyncCorebtn_Click"))
                //                {
                //                    throw new Exception("因为k==11_AsyncCorebtn_Click, 所以就异常了");
                //                }
                //                else if (k.Equals("16_AsyncCorebtn_Click"))
                //                {
                //                    throw new Exception("因为k==16_AsyncCorebtn_Click, 所以就异常了");
                //                }
                //            //}
                //            //catch (Exception)
                //            //{

                //            //} 
                //        }));
                //    } 
                //    //现成的同步等待 
                //    //Task.WaitAll(tasklist.ToArray());
                //}
                //catch (AggregateException ext)
                //{
                //    foreach (var exception in ext.InnerExceptions)
                //    {
                //        Console.WriteLine(exception.Message);
                //    }
                //}
                //catch (Exception ex)
                //{

                //}
            }
            #endregion



            //来一个开发的故事~~ 
            //系统---首页[包含了很多块的内容].  数据的来源不一样的.   可以启动多个线程同时去查询. 等待线程执行完毕.  都取到数据之后.  统一返回.

            //首页中包含的数据库. 必须保证所有的数据都是正常的.
            //如果有一个或者是几个线程发生了故障. 异常了. 导致整体的数据不完整.  数据不完整, 数据肯定就不能用.  就要重新获取数据.
            //正常执行的线程,  有必要执行下去吗?  没有必要执行了.
            //就需要线程取消.


            //二.线程 取消~~ 
            #region 线程取消    
            //1.  线程是不能从外部取消的. 只能自己取消自己. 只有上帝才能打败上帝,  只有上帝才能制造出一块上帝搬不动的石头. 
            //2. 不能从外部取消, 只能让让他自己取消自己. 信号量.
            //3.多线程的执行.  线程的启动  是向操作系统去调用线程任务. 然后调度到线程后, 再使用这个线程来做事儿.  线程是延迟启动~~   如果启动的多个线程, 如果已经启动了5个线程.  还有三个线程准备启动,但是还没有启动.---还没有启动的线程就应该不要启动了~~
            {
                ////多线程内部发生了异常后, 线程就自动取消了.
                ////bool isGoOn = true;  //可以--不推荐---线程不安全问题.

                ////线程取消的标准方案;
                ////1.定义cts--- 包含了一个IsCancellationRequested属性, 默认值为false;  默认不取消;
                ////cts 包含了一个方法 Cancel方法.  Cancel方法的执行.IsCancellationRequested 的值  变成true.
                //CancellationTokenSource cts = new CancellationTokenSource();

                //for (int i = 0; i < 50; i++)
                //{
                //    string k = $"{i}_AsyncCorebtn_Click";
                //    Task.Run(() =>
                //     {
                //         Thread.Sleep(new Random().Next(10,30)); 
                //         if (k.Equals("6_AsyncCorebtn_Click"))
                //         {
                //             cts.Cancel();
                //         }

                //         if (cts.IsCancellationRequested)
                //         {
                //             Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString()} 没有正常开始~~"); 
                //             cts.Cancel();
                //             throw new Exception();
                //         }
                //         else
                //         {
                //             Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString()} 正常开始~~");
                //         }
                          
                //         {
                //             //中间可能有大量的业务逻辑执行;
                //         }

                //         {
                //             if (cts.IsCancellationRequested)
                //             {
                //                 Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString()} 没有正常结束~~");
                //                 cts.Cancel();

                //             }
                //             else
                //             {
                //                 Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString()} 正常结束~~");
                //             }
                //         } 

                //     }, cts.Token);
                //}
            }
            #endregion

            #region 临时变量
            //为什么i的值有20个值,  为什么每个值都是20呢?

            //1.多线程启动, 不阻塞主线程;
            //2.线程是延迟启动---延迟的时间很短的.
            {
                for (int i = 0; i < 20; i++)
                { 
                    string k=i.ToString();
                    Task.Run(() =>
                    {
                        Console.WriteLine($"i的值:{i}   k的值是{k}");
                    });
                }


                //请问: 上面这个代码执行完毕, i 的值是多少?
                //1. 0. 1. 2. 3. 4. 5. 6. 7.... 一直到20
                //2. 都是19
                //3. 都是20.  



            }

            #endregion

            #region 线程安全&lock   
            {
                //{
                //    Num = 0;
                //    for (int i = 0; i < 10000; i++)
                //    {
                //        Num++;
                //    }
                //    Console.WriteLine($"Num is {Num}");  //Num 最后：值为多少？9999 /10000
                //}
                //{
                //    List<Task> tasks = new List<Task>();
                //    AsyncNum = 0;
                //    for (int i = 0; i < 10000; i++)
                //    {
                //        tasks.Add(Task.Run(() =>
                //        {
                //            AsyncNum++;
                //        }));
                //    }
                //    Task.WaitAll(tasks.ToArray());
                //    Console.WriteLine($"AsyncNum is {AsyncNum}");   //AsyncNum 最后：  9999/ <10000
                //}

                //ParallelOptions parallelOptions=new ParallelOptions();
                //parallelOptions.MaxDegreeOfParallelism = 10;
                //Parallel.ForEach<int>(source =>
                //{

                //}, parallelOptions);



            }
            #endregion

            Console.WriteLine($"****************AsyncCorebtn_Click End  ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        private static readonly object obj_Lock = new object(); //锁一定要锁对象  静态对象

        private int Num = 0;
        private int AsyncNum = 0;



    }
}
